package com.wx.wechat.service.impl;

import com.wx.commons.utils.enums.EnumsUtils;
import com.wx.core.exception.BusinessJsonException;
import com.wx.wechat.Interface.WeChatPay;
import com.wx.wechat.config.WeChatConfig;
import com.wx.wechat.config.WechatAPI;
import com.wx.wechat.enums.status.WeChatEnumStatus;
import com.wx.wechat.request.Refund;
import com.wx.wechat.request.Unifiedorder;
import com.wx.wechat.service.WeChatPayService;
import com.wx.wechat.utils.WechatUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import org.apache.commons.lang3.StringUtils;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.wx.wechat.constant.WechatParameterName.WechatRequest.*;

/**
 * @author wx
 * @Description: 微信支付业务层
 * @date 2018/11/5 000517:12
 */
@Slf4j
public class WeChatPayServiceImpl implements WeChatPayService {
    private WeChatConfig weChatConfig;

    public void setWeChatConfig(WeChatConfig weChatConfig) {
        this.weChatConfig = weChatConfig;
    }


    /**
     * @param unifiedorder
     * @description: 微信统一下单  场景：公共号支付、扫码支付、APP支付
     * @author: wx
     * @date: 2018/11/2 0002
     * @return: java.util.Map<java.lang.String                                                               ,                               java.lang.String>
     */
    @Override
    public Map<String, String> unifiedOrder(Unifiedorder unifiedorder) throws BusinessJsonException {
        //获取封装好的请求参数
        Map<String, String> fillRequestData = unifiedorder.initRequestParameter(fillRequestData());
        //生成签名
        fillRequestData.put(REQUEST_SIGN, WechatUtil.generateSignature(fillRequestData, weChatConfig.getKey(), fillRequestData.get(REQUEST_SIGN_TYPE)));
        String reqBody = WechatUtil.mapToXml(fillRequestData);
        RequestBody route = RequestBody.create(MediaType.parse("application/xml;charset=UTF-8"), reqBody);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(WechatAPI.DOMAIN_PAY)
                .addConverterFactory(SimpleXmlConverterFactory.create())
                .build();
        Call<ResponseBody> responseBodyCall = retrofit.create(WeChatPay.class).unifiedOrder(route);
        try {
            String responseBodyString = responseBodyCall.execute().body().string();
            Map<String, String> responseBodyMap = WechatUtil.xmlToMap(responseBodyString);
            WechatUtil.validationResponseSignature(responseBodyMap, fillRequestData.get(REQUEST_SIGN_TYPE), weChatConfig.getKey());
            return responseBodyMap;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信统一下单请求失败");
        }

    }

    /**
     * @param productId 商品id
     * @param signType  签名类型
     * @description: 生成微信收款二维
     * @author: wx
     * @date: 2018/11/5 0005
     * @return: java.lang.String
     */
    @Override
    public String getWechatPayQrCode(String productId, Integer signType) throws BusinessJsonException {
        Map<String, String> reqData = fillRequestData();
        reqData.put(REQUEST_SIGN_TYPE, EnumsUtils.getEnumMeesge(WeChatEnumStatus.SignType.class, signType));
        reqData.put(REQUEST_SIGN, WechatUtil.generateSignature(reqData, weChatConfig.getKey(), reqData.get(REQUEST_SIGN_TYPE)));
        return String.format(WechatAPI.WECHAT_PAY_QR_CODE_URL, weChatConfig.getAppId(),
                weChatConfig.getMchId(), reqData.get(REQUEST_NONCE_STR), productId, System.currentTimeMillis() / 1000,
                reqData.get(REQUEST_SIGN));
    }


    /**
     * @param notifyData 异步通知数据
     * @param signType   签名方式
     * @description: 验证异步通知签名并获取结果
     * @author: wx
     * @date: 2018/11/5 0005
     * @return: java.util.Map<java.lang.String,java.lang.String>
     */
    @Override
    public Map<String, String> asyncNotify(String notifyData, Integer signType) throws BusinessJsonException {
        Map<String, String> responseBodyMap = WechatUtil.xmlToMap(notifyData);
        WechatUtil.validationResponseSignature(responseBodyMap, responseBodyMap.get(REQUEST_SIGN_TYPE), weChatConfig.getKey());
        return responseBodyMap;
    }

    /**
     * @param refund
     * @description: 申请退款 刷卡支付、公共号支付、扫码支付、APP支付
     * @author: wx
     * @date: 2018/11/5 0005
     * @return: java.util.Map<java.lang.String, java.lang.String>
     */
    @Override
    public Map<String, String> refund(Refund refund) throws BusinessJsonException {
        //获取封装好的请求参数
        Map<String, String> fillRequestData = refund.initRequestParameter(fillRequestData());
        //生成签名
        fillRequestData.put(REQUEST_SIGN, WechatUtil.generateSignature(fillRequestData, weChatConfig.getKey(), fillRequestData.get(REQUEST_SIGN_TYPE)));
        String reqBody = WechatUtil.mapToXml(fillRequestData);
        RequestBody route = RequestBody.create(MediaType.parse("application/xml;charset=UTF-8"), reqBody);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(WechatAPI.DOMAIN_PAY)
                .addConverterFactory(SimpleXmlConverterFactory.create())
                .build();
        //TODO 此处需要配置双向证书
        Call<ResponseBody> responseBodyCall = retrofit.create(WeChatPay.class).refund(route);
        try {
            String responseBodyString = responseBodyCall.execute().body().string();
            Map<String, String> responseBodyMap = WechatUtil.xmlToMap(responseBodyString);
            WechatUtil.validationResponseSignature(responseBodyMap, fillRequestData.get(REQUEST_SIGN_TYPE), weChatConfig.getKey());
            return responseBodyMap;
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessJsonException("微信申请退款请求失败");
        }
    }

    /**
     * @description: 该函数初始化基础数据适用于商户适用于统一下单等接口，不适用于红包、代金券接口
     * @author: wx
     * @date: 2018/9/5 0005
     * @return: java.util.Map<java.lang.String   ,   java.lang.String>
     */
    private Map<String, String> fillRequestData() {
        HashMap<String, String> reqData = new HashMap<>();
        if (StringUtils.isNotBlank(weChatConfig.getAppId())) {
            reqData.put(REQUEST_APP_ID, weChatConfig.getAppId());
        }
        if (StringUtils.isNotBlank(weChatConfig.getMchId())) {
            reqData.put(REQUEST_MCH_ID, weChatConfig.getMchId());
        }
        if (StringUtils.isNotBlank(weChatConfig.getSubAppId())) {
            reqData.put(REQUEST_SUB_APPID, weChatConfig.getSubAppId());
        }
        if (StringUtils.isNotBlank(weChatConfig.getSubMchId())) {
            reqData.put(REQUEST_SUB_MCH_ID, weChatConfig.getSubMchId());
        }
        reqData.put(REQUEST_NONCE_STR, WechatUtil.generateNonceStr());
        return reqData;
    }
}
